﻿/**
 * This software is released under the MIT License
 * 
 * Copyright (c) 2009 Philippe Van Kessel
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package com.calefk.util
{
	import flash.display.Sprite;
	
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flash.geom.Matrix;
	
	public class Stretcher extends DistortGrid
	{
		// Reference to the 4 corners. If you change the position of a corner, you must call updateGrid for the change to take effect.
		// Please refer to the setTransform method summary to to know which variable corresponds to which corner.
		public var _c1:Point, _c2:Point, _c3:Point, _c4:Point;
		
		
		// ---------------------------------------------------------------------------------------------------------
		//	Initialization
		// ---------------------------------------------------------------------------------------------------------
		
		/**
		 * Constructor.
		 * 
		 * @param	$container	The MovieClip which will contain the stretched MovieClip
		 * @param	$source		The BitmapData, Sprite or Shape to stretch
		 * @param	$nc			The number of columns (horizontal precision). Default value is 1
		 * @param	$nr			The number of rows (vertical precision). Default value is 1
		 */
		public function Stretcher($container:Sprite, $source:Sprite, $nc:int, $nr:int)
		{
			super($container, $source, $nc, $nr);
			
			_c1 = _pp[0][0];
			_c2 = _pp[0][_nc];
			_c3 = _pp[_nr][0];
			_c4 = _pp[_nr][_nc];
		}
		
		/**
		 * Clears every property to make them elibigle for garbage collection.
		 */
		public override function clear():void
		{
			super.clear();
			
			_c1 = null;
			_c2 = null;
			_c3 = null;
			_c4 = null;
		}
		
		
		
		// ---------------------------------------------------------------------------------------------------------
		//	Public methods
		// ---------------------------------------------------------------------------------------------------------
		
		/**
		 * Places the four corners in one call.
		 * 
		 * @param	$c1x	x position of the top left corner (_c1.x)
		 * @param	$c1y	y position of the top left corner (_c1.y)
		 * @param	$c2x	x position of the top right corner (_c2.x)
		 * @param	$c2y	y position of the top right corner (_c2.y)
		 * @param	$c3x	x position of the bottom left corner (_c3.x)
		 * @param	$c3y	y position of the bottom left corner (_c3.y)
		 * @param	$c4x	x position of the bottom right corner (_c4.x)
		 * @param	$c4y	y position of the bottom right corner (_c4.y)
		 */
		public function setTransform($c1x:Number, $c1y:Number, $c2x:Number, $c2y:Number, $c3x:Number, $c3y:Number, $c4x:Number, $c4y:Number):void
		{
			_c1.x = $c1x;
			_c1.y = $c1y;
			
			_c2.x = $c2x;
			_c2.y = $c2y;
			
			_c3.x = $c3x;
			_c3.y = $c3y;
			
			_c4.x = $c4x;
			_c4.y = $c4y;
			
			updateGrid();
		}
		
		/**
		 * Change the number of columns (horizontal precision).
		 * 
		 * @param	$v	The new number of columns
		 */
		public function resizeCols($v:int):void
		{
			$v = isNaN($v) || $v < 1 ? 1 : $v;
			if (_nc == $v) return;
			
			var ir:int, ic:int;
			
			if ($v <= _nc) // less columns than before
			{
				for (ir = 0 ; ir <= _nr ; ir++)
					_pp[ir].splice($v + 1);
			}
			else
			{
				_pp[0][_nc] = new Point(0, 0);
				_pp[_nr][_nc] = new Point(0, 0);
				
				for (ir = 0 ; ir <= _nr ; ir++)
				{
					for (ic = _nc+1 ; ic <= $v ; ic++)
						_pp[ir][ic] = new Point(0, 0);
				}
			}
			
			_nc = $v;
			_lx = _w / _nc;
			
			_pp[0][_nc] = _c2;
			_pp[_nr][_nc] = _c4;
			
			updateGrid();
		}
		
		/**
		 * Change the number of rows (vertical precision).
		 * 
		 * @param	$v	The new number of rows
		 */
		public function resizeRows($v:int):void
		{
			$v = isNaN($v) || $v < 1 ? 1 : $v;
			if (_nr == $v) return;
			
			if ($v < _nr)
			{
				_pp.splice($v+1);
			}
			else
			{
				var ir:int, ic:int;
				
				_pp[_nr][0] = new Point(0, 0);
				_pp[_nr][_nc] = new Point(0, 0);
				
				for (ir = _nr + 1 ; ir <= $v ; ir++)
				{
					_pp[ir] = [];
					
					for (ic = 0 ; ic <= _nc ; ic++)
						_pp[ir][ic] = new Point(0, 0);
				}
			}
			
			_nr = $v;
			_ly = _h / _nr;
			
			_pp[_nr][0] = _c3;
			_pp[_nr][_nc] = _c4;
			
			updateGrid();
		}
		
		/**
		 * Adjusts grid points to the four corners and then calls the render method.
		 */
		public function updateGrid():void
		{
			var x1:Number, x2:Number, y1:Number, y2:Number, dx1:Number, dx2:Number, dy1:Number, dy2:Number, r:Array, ir:int, ic:int;
			
			x1 = _c1.x;
			y1 = _c1.y;
			dx1 = (_c3.x - _c1.x) / _nr;
			dy1 = (_c3.y - _c1.y) / _nr;
			
			x2 = _c2.x;
			y2 = _c2.y;
			dx2 = (_c4.x - _c2.x) / _nr;
			dy2 = (_c4.y - _c2.y) / _nr;
			
			for (ir = 1 ; ir < _nr ; ir++)
			{
				r = _pp[ir];
				
				r[0].x = (x1 += dx1);
				r[0].y = (y1 += dy1);
				
				r[_nc].x = (x2 += dx2);
				r[_nc].y = (y2 += dy2);
			}
			
			for (ir = 0 ; ir <= _nr ; ir++)
			{
				r = _pp[ir];
				
				x1 = r[0].x;
				y1 = r[0].y;
				dx1 = (r[_nc].x - x1) / _nc;
				dy1 = (r[_nc].y - y1) / _nc;
				
				for (ic = 1 ; ic < _nc ; ic++)
				{
					r[ic].x = (x1 += dx1);
					r[ic].y = (y1 += dy1);
				}
			}
			
			render();
		}
	}
}